home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / vbcc / pasm / pass.c < prev    next >
C/C++ Source or Header  |  1998-06-24  |  12KB  |  455 lines

  1. /* $VER: pasm pass.c V0.6 (26.10.97)
  2.  *
  3.  * This file is part of pasm, a portable PowerPC assembler.
  4.  * Copyright (c) 1997  Frank Wille
  5.  *
  6.  * pasm is freeware and part of the portable and retargetable ANSI C
  7.  * compiler vbcc, copyright (c) 1995-97 by Volker Barthelmann.
  8.  * pasm may be freely redistributed as long as no modifications are
  9.  * made and nothing is charged for it. Non-commercial usage is allowed
  10.  * without any restrictions.
  11.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  12.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  13.  *
  14.  *
  15.  * v0.6 (26.10.97) phx
  16.  *      Bug in conditional assembly fixed.
  17.  *      @object and @function symbols are always defined before
  18.  *      pass 1 is executed.
  19.  * v0.5 (12.10.97) phx
  20.  *      Support for user symbol definitions by -D option.
  21.  *      The opcode field is automatically converted to lower case,
  22.  *      so upper case directives and instructions are also allowed.
  23.  * v0.3 (10.04.97) phx
  24.  *      Some vbcc-specific changes.
  25.  * v0.2 (25.03.97) phx
  26.  *      Writes ELF object for 32-bit PowerPC big-endian. Either absolute
  27.  *      or ELF output format may be selected. ELF is default for all
  28.  *      currently supported platforms. PPCasm supports nine different
  29.  *      relocation types (there are much more...).
  30.  *      Compiles and works also under NetBSD/amiga (68k).
  31.  *      Changed function declaration to 'new style' in all sources
  32.  *      (to avoid problems with '...' for example).
  33.  * v0.1 (11.03.97) phx
  34.  *      First test version with all PowerPC instructions and most
  35.  *      important directives. Only raw, absolute output.
  36.  * v0.0 (15.02.97) phx
  37.  *      File created.
  38.  */
  39.  
  40.  
  41. #define PASS_C
  42. #include "ppcasm.h"
  43.  
  44.  
  45. void exec_pass1(struct GlobalVars *);
  46. void pass1(struct GlobalVars *,struct SourceText *,
  47.            struct MacroParams *,struct SourceThread *);
  48. struct SourceText *include_source(struct GlobalVars *,char *);
  49. void exec_pass2(struct GlobalVars *);
  50. void pass2(struct GlobalVars *,struct SourceText *,
  51.            struct MacroParams *,struct SourceThread *);
  52. struct SourceText *get_source(struct GlobalVars *);
  53.  
  54. static char *insert_macro_params(struct GlobalVars *,struct ParsedLine *,
  55.                                  char *,struct MacroParams *);
  56. static char *readline(struct GlobalVars *,struct ParsedLine *,char *);
  57. static char *getlabel(struct GlobalVars *,char *);
  58. static struct SourceText *add_source(struct GlobalVars *,char *,char *,long);
  59. static void prepare_sections(struct GlobalVars *);
  60.  
  61.  
  62.  
  63. void exec_pass1(struct GlobalVars *gv)
  64. {
  65.   struct Symbol *sym;
  66.   char asmname[20];
  67.   char **p,*xmnemobuf,*usrdefbuf;
  68.   size_t xmsize=0,udsize=0;
  69.   struct UserDefine *nextudn;
  70.   struct UserDefine *udn = (struct UserDefine *)gv->userdeflist.first;
  71.  
  72.   sprintf(asmname,PNAME "_V%d.%02d",VERSION,REVISION);
  73.   sym = add_symbol(gv,asmname,SYM_ABS,0);
  74.   sym->bind = SYMB_LOCAL;
  75.   gv->lcsym = add_symbol(gv,"$",SYM_RELOC,0);
  76.   gv->nargsym = add_symbol(gv,"$NARG",SYM_ABS,0);
  77.   add_symbol(gv,"@object",SYM_ABS,1);
  78.   add_symbol(gv,"@function",SYM_ABS,2);
  79.   gv->ifcond[0] = TRUE;
  80.  
  81.   pass1(gv,add_source(gv,"<standard sections>",stdsects,
  82.         strlen(stdsects)),NULL,NULL);
  83.  
  84.   if (!gv->noregsymbols)
  85.     pass1(gv,add_source(gv,"<standard definitions>",stdsets,
  86.           strlen(stdsets)),NULL,NULL);
  87.  
  88.   while (nextudn = (struct UserDefine *)udn->n.next) {
  89.     udsize += strlen(udn->line);
  90.     udn = nextudn;
  91.   }
  92.   if (udsize) {
  93.     usrdefbuf = alloc(udsize+1);
  94.     *usrdefbuf = 0;
  95.     while (udn = (struct UserDefine *)remhead(&gv->userdeflist)) {
  96.       strcat(usrdefbuf,udn->line);
  97.       free(udn->line);
  98.       free(udn);
  99.     }
  100.     gv->usrdefs = TRUE;
  101.     pass1(gv,add_source(gv,"<user definitions>",usrdefbuf,udsize),
  102.           NULL,NULL);
  103.   }
  104.  
  105.   if (!gv->noextmnemo) {
  106.     p = xmnemos;
  107.     while (*p) {
  108.       xmsize += strlen(*p);
  109.       p++;
  110.     }
  111.     xmnemobuf = alloc(xmsize+1);
  112.     *xmnemobuf = 0;
  113.     p = xmnemos;
  114.     while (*p) {
  115.       strcat(xmnemobuf,*p);
  116.       p++;
  117.     }
  118.     pass1(gv,add_source(gv,"<extended mnemonics>",xmnemobuf,xmsize),
  119.           NULL,NULL);
  120.   }
  121.  
  122.   pass1(gv,include_source(gv,gv->source_name),NULL,NULL);
  123.   if (gv->vc) {
  124.     activate_section(gv,(struct Section *)gv->sectionlist.first);
  125.     alignment(gv,2);
  126.     pcadd(gv,4);
  127.   }
  128. }
  129.  
  130.  
  131. void pass1(struct GlobalVars *gv,struct SourceText *srctxt,
  132.            struct MacroParams *macro,struct SourceThread *prev_st)
  133. /* Assembler Pass 1 */
  134. {
  135.   struct SourceThread st;
  136.   unsigned long nlines = srctxt->nlines;
  137.   char *lp,c;
  138.   struct ParsedLine *pl = srctxt->plin;
  139.  
  140.   /* init SourceThread structure */
  141.   st.prev = prev_st;
  142.   st.macro = macro;
  143.   st.csource = srctxt;
  144.   st.srcptr = srctxt->text;  /* current source pointer */
  145.   st.line = 1;
  146.   st.macskip = NULL;
  147.   gv->cthread = &st;  /* set current source thread */
  148.  
  149.   while (nlines--) {
  150.     gv->absline++;
  151.     pl->lineptr = st.lineptr = st.srcptr;
  152.  
  153.     /* get next line of source text */
  154.     if (macro && gv->ifcond[gv->iflevel]) {  /* insert macro parameters? */
  155.       st.srcptr = insert_macro_params(gv,pl,st.srcptr,macro);
  156.     }
  157.     else {
  158.       st.srcptr = readline(gv,pl,st.srcptr);
  159.     }
  160.     lp = gv->linebuf;
  161.  
  162.     /* evaluate label field */
  163.     lp = getlabel(gv,lp);
  164.     if (*gv->strbuf)
  165.       if (!st.macskip && gv->ifcond[gv->iflevel])
  166.         add_symbol(gv,gv->strbuf,SYM_RELOC,gv->csect->pc);
  167.     lp = skipspaces(lp);
  168.  
  169.     /* evaluate opcode field */
  170.     lp = getsymbol(gv,lp);
  171.     if (*gv->strbuf) {
  172.       lower_case(gv->strbuf);  /* convert opcode to lower case */
  173.  
  174.       if (st.macskip) {  /* macros */
  175.         if (!strcmp(gv->strbuf,".endm")) {
  176.           st.macskip->nlines = gv->absline - st.macskip->nlines;
  177.           add_macro(gv,st.macskip);
  178.           st.macskip = NULL;
  179.         }
  180.       }
  181.  
  182.       else if (!gv->ifcond[gv->iflevel]) {  /* conditional assembly */
  183.         if (!strncmp(gv->strbuf,".if",3))
  184.           gv->ifignore++;
  185.         else if (!strcmp(gv->strbuf,".else")) {
  186.           if (gv->ifignore == 0)
  187.             gv->ifcond[gv->iflevel] = TRUE;
  188.         }
  189.         else if (!strcmp(gv->strbuf,".endif")) {
  190.           if (gv->ifignore)
  191.             gv->ifignore--;
  192.           else
  193.             gv->iflevel--;
  194.         }
  195.       }
  196.  
  197.       else {  /* search opcode */
  198.         c = *lp;  /* branch hint given? */
  199.         if (c=='+') {
  200.           lp++;
  201.           pl->branch_hint = 1;
  202.         }
  203.         else if (c=='-') {
  204.           lp++;
  205.           pl->branch_hint = -1;
  206.         }
  207.         search_opcode(gv,pl,gv->strbuf,skipspaces(lp));
  208.       }
  209.     }
  210.  
  211.     if (!(pl->flags&PLF_NONEWLINE))
  212.       st.line++;
  213.     ++pl;
  214.   }
  215.   gv->cthread = prev_st;
  216. }
  217.  
  218.  
  219. static char *insert_macro_params(struct GlobalVars *gv,struct ParsedLine *pl,
  220.                                  char *s,struct MacroParams *mp)
  221. {
  222.   char **par = mp->param;
  223.   char c,callidbuf[16];
  224.   char *pp,*d=gv->linebuf;
  225.   int n;
  226.  
  227.   do {
  228.     if ((c=*s++) == '\\') {
  229.       if (*s>='0' && *s<='9') {  /* macro parameter? */
  230.         n = (int)(*s++ - '0');
  231.         if (pp = par[n]) {
  232.           while (*d++ = *pp++);  /* insert parameter */
  233.           d--;
  234.           continue;
  235.         }
  236.         else {
  237.           error(9,n);  /* reference to undefined macro parameter n */
  238.           continue;
  239.         }
  240.       }
  241.       else if (*s=='@') {  /* insert macro call id */
  242.         s++;
  243.         pp = callidbuf;
  244.         sprintf(pp,"$%d",(int)mp->call_id);
  245.         while (*d++ = *pp++);
  246.         d--;
  247.         continue;
  248.       }
  249.     }
  250.     *d++ = c;
  251.   }
  252.   while (c!=0 && c!=1);
  253.   if (c==1) {
  254.     *(--d) = 0;
  255.     pl->flags |= PLF_NONEWLINE;
  256.   }
  257.   return (s);
  258. }
  259.  
  260.  
  261. static char *readline(struct GlobalVars *gv,struct ParsedLine *pl,char *s)
  262. {
  263.   char c,*d = gv->linebuf;
  264.  
  265.   do {
  266.     c = *s++;
  267.     *d++ = c;
  268.   }
  269.   while (c!=0 && c!=1);
  270.   if (c==1) {
  271.     *(--d) = 0;
  272.     pl->flags |= PLF_NONEWLINE;
  273.   }
  274.   return (s);
  275. }
  276.  
  277.  
  278. static char *getlabel(struct GlobalVars *gv,char *s)
  279. /* read label to gv->strbuf, s points to the beginning of a line */
  280. {
  281.   char *s_old = s;
  282.  
  283.   s = getsymbol(gv,s);  /* read label to buffer */
  284.   if ((s != s_old) && (*s == ':'))  /* colon indicates a valid label */
  285.     return (++s);
  286.   *gv->strbuf = 0;
  287.   return (s_old);
  288. }
  289.  
  290.  
  291. struct SourceText *include_source(struct GlobalVars *gv,char *name)
  292. /* called when encountering an .include directive */
  293. {
  294.   char *s = mapfile(gv,name);
  295.   long len = *(size_t *)(s - sizeof(size_t));  /* mapfile stores size here */
  296.  
  297.   return (add_source(gv,name,s,len));
  298. }
  299.  
  300.  
  301. static struct SourceText *add_source(struct GlobalVars *gv,char *name,
  302.                                      char *s,  /* source text pointer */
  303.                                      long len) /* text length in bytes */
  304. /* create a new SourceText node and add it to the source list */
  305. {
  306.   struct SourceText *stxt = alloc(sizeof(struct SourceText));
  307.   bool comm=FALSE;
  308.   char quote=0;
  309.  
  310.   stxt->name = name;
  311.   stxt->text = s;
  312.   stxt->nlines = 0;
  313.  
  314.   /* replace '\n' and ';' by \0 and determine number of lines */
  315.   for (; len>0; len--,s++) {
  316.     switch (*s) {
  317.       case '\n':
  318.         *s = 0;
  319.         stxt->nlines++;
  320.         comm = FALSE;  /* \n ends a comment */
  321.         break;
  322.       case '\r':  /* ignore CRs */
  323.         *s = 0;
  324.         break;
  325.       case ';':   /* ';' allows multiple statements per line */
  326.         if (!comm && !quote) {
  327.           if (*(s+1)=='\n' || *(s+1)=='\r')
  328.             *s = ' ';
  329.           else {
  330.             *s = 1;
  331.             stxt->nlines++;
  332.           }
  333.         }
  334.         break;
  335.       case '#':   /* comment: ignore ';' in rest of line */
  336.         comm = TRUE;
  337.         break;
  338.       case 0x22:  /* ignore ';' in strings too */
  339.         if (quote==0x22)
  340.           quote = 0;
  341.         else if (!quote)
  342.           quote = 0x22;
  343.         break;
  344.       case 0x27:
  345.         if (quote==0x27)
  346.           quote = 0;
  347.         else if (!quote)
  348.           quote = 0x27;
  349.         break;
  350.     }
  351.   }
  352.  
  353.   stxt->plin = alloczero(stxt->nlines * sizeof(struct ParsedLine));
  354.   addtail(&gv->sourcelist,&stxt->n);
  355.   return (stxt);
  356. }
  357.  
  358.  
  359. static void prepare_sections(struct GlobalVars *gv)
  360. /* prepare sections for receiving code in pass 2 */
  361. {
  362.   struct Section *nexts,*sec=(struct Section *)gv->sectionlist.first;
  363.  
  364.   while (nexts = (struct Section *)sec->n.next) {
  365.     sec->size = sec->pc;
  366.     sec->pc = 0;
  367.     if (!(sec->flags & SF_UNINITIALIZED))
  368.       if (sec->size)
  369.         sec->data = sec->contents = alloc((size_t)sec->size);
  370.     sec = nexts;
  371.   }
  372. }
  373.  
  374.  
  375. void exec_pass2(struct GlobalVars *gv)
  376. {
  377.   gv->absline = 0;
  378.   gv->pass = 1;
  379.   prepare_sections(gv);
  380.  
  381.   pass2(gv,get_source(gv),NULL,NULL);  /* <standard sections> */
  382.   if (!gv->noregsymbols)
  383.     pass2(gv,get_source(gv),NULL,NULL);  /* <standard definitions> */
  384.   if (gv->usrdefs)
  385.     pass2(gv,get_source(gv),NULL,NULL);  /* <user definitions> */
  386.   if (!gv->noextmnemo)
  387.     pass2(gv,get_source(gv),NULL,NULL);  /* <extended mnemonics> */
  388.  
  389.   pass2(gv,get_source(gv),NULL,NULL); 
  390.   if (gv->vc) {
  391.     activate_section(gv,(struct Section *)gv->sectionlist.first);
  392.     alignment(gv,2);
  393.     store_word(gv,0x76626363);
  394.   }
  395. }
  396.  
  397.  
  398. void pass2(struct GlobalVars *gv,struct SourceText *srctxt,
  399.            struct MacroParams *macro,struct SourceThread *prev_st)
  400. /* Assembler Pass 2 */
  401. {
  402.   struct SourceThread st;
  403.   unsigned long nlines = srctxt->nlines;
  404.   struct ParsedLine *pl = srctxt->plin;
  405.   uint32 oldnarg;
  406.  
  407.   /* init SourceThread structure */
  408.   st.prev = prev_st;
  409.   st.macro = macro;
  410.   st.csource = srctxt;
  411.   st.line = 1;
  412.   gv->cthread = &st;  /* set current source thread */
  413.  
  414.   while (nlines--) {
  415.     gv->absline++;
  416.     st.lineptr = pl->lineptr;
  417.  
  418.     /* evaluate opcode field */
  419.     switch (pl->type) {
  420.  
  421.       case OT_INSTRUCTION:
  422.         instr(gv,pl);
  423.         break;
  424.  
  425.       case OT_DIRECTIVE:
  426.         (((struct Directive *)pl->opcode)->dfunct)(gv,pl);
  427.         break;
  428.  
  429.       case OT_MACRO:
  430.         oldnarg = gv->nargsym->value;
  431.         gv->nargsym->value = (uint32)pl->narg;
  432.         pass2(gv,get_source(gv),(struct MacroParams *)gv,gv->cthread);
  433.         /* the MacroParams pointer is set to gv, because we */
  434.         /* only need a non-zero pointer here... */
  435.         gv->nargsym->value = oldnarg;
  436.         break;
  437.  
  438.       case OT_SECTION:
  439.         activate_section(gv,(struct Section *)pl->opcode);
  440.         break;
  441.     }
  442.  
  443.     if (!(pl->flags&PLF_NONEWLINE))
  444.       st.line++;
  445.     ++pl;
  446.   }
  447.   gv->cthread = prev_st;
  448. }
  449.  
  450.  
  451. struct SourceText *get_source(struct GlobalVars *gv)
  452. {
  453.   return ((struct SourceText *)remhead(&gv->sourcelist));
  454. }
  455.